package com.winit.openapi.tp.controller;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alibaba.fastjson.JSONObject;
import com.winit.common.spi.context.CommandContext;
import com.winit.openapi.constants.ErrorCode;
import com.winit.openapi.controller.BaseController;
import com.winit.openapi.exception.ApiException;
import com.winit.openapi.model.RequestMsg;
import com.winit.openapi.model.ResponseMsg;
import com.winit.openapi.tp.bo.TraceBO;
import com.winit.openapi.tp.bo.TraceVo;
import com.winit.openapi.tp.bo.TrackingBO;
import com.winit.openapi.tp.bo.TrackingVo;
import com.winit.openapi.tp.manager.TrackingComparetor;
import com.winit.openapi.util.DateUtil;
import com.winit.tp.spi.trace.TrackingService;
import com.winit.tp.spi.trace.command.BatchQueryTrackingCommand;

/**
 * <Change to the actual description of this class>
 * 
 * @version <pre>
 * Author   Version     Date        Changes
 * liang.lu     1.0         Mar 9, 2015     Created
 * 
 * </pre>
 * @since 1.
 */
@Controller
@RequestMapping(value = "/tracking")
public class TrackingController extends BaseController {
    
    private Logger                               logger = LoggerFactory.getLogger(TrackingController.class);

    @Resource
    private TrackingService trackingService;
    
    private final String PARAM_TRACKINGNOS_LOWER = "trackingnos";
    private final String PARAM_TRACKINGNOS = "trackingNos";

    @RequestMapping(value = "/getOrderTracking")
    public String queryTracking(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
    	
        Object obj = requestMsg.getData();
        BatchQueryTrackingCommand command = null;
        if (!(obj instanceof JSONObject)) {
        	throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        long start = System.currentTimeMillis();
        try {
            JSONObject json = (JSONObject) obj;
            command = this.buildBatchQueryCommand(json);
            if(StringUtils.isNotEmpty(requestMsg.getPlatform())){
            	command.setPlatform(requestMsg.getPlatform());
            }else{
            	//默认 第三方平台接口调用
            	command.setPlatform("thirdparty");
            }
            // 调用接口查询订单
            if (null != command.getKeys()) {
                List<com.winit.tp.spi.trace.vo.TrackingVo> result = trackingService.batchQueryTracking(command);
                List<TrackingVo> data = new ArrayList<TrackingVo>();
                if (!CollectionUtils.isEmpty(result)) {
                	 data = this.buildTrackingFromList(result,command.getCtx().getLanguageCountry());// 数据转换
                    /* TrackingComparetor comparetor = new TrackingComparetor();
                     Collections.sort(data, comparetor);*/// 数据排序
                } 
                responseMsg.setData(data);
            }
        } finally {
            long end = System.currentTimeMillis();
            logger.info("轨迹处理getOrderTracking,耗时:{}", (end - start)/1000f);
        }
        return SUCCESS;
    }

    
    @RequestMapping(value = "/getOrderVerdorTracking")
    public String queryVerdorTracking(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
    	
        Object obj = requestMsg.getData();
        BatchQueryTrackingCommand command = null;
        if (!(obj instanceof JSONObject)) {
        	throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        long start = System.currentTimeMillis();
        try {
            JSONObject json = (JSONObject) obj;
            command = this.buildBatchQueryCommand(json);
            
            if(StringUtils.isNotEmpty(requestMsg.getPlatform())){
            	command.setPlatform(requestMsg.getPlatform());
            }else{
            	//默认 第三方平台接口调用
            	command.setPlatform("thirdparty");
            }
            // 调用接口查询订单
            if (null != command.getKeys()) {
                List<com.winit.tp.spi.trace.vo.TrackingVo> result = trackingService.batchQueryTracking(command);
                List<TrackingVo> data = this.buildVerdorTrackingFromList(result,command.getCtx().getLanguageCountry());// 数据转换
                TrackingComparetor comparetor = new TrackingComparetor();
                Collections.sort(data, comparetor);// 数据排序
                responseMsg.setData(data);
            }
        } finally {
            long end = System.currentTimeMillis();
            logger.info("轨迹处理getOrderTracking,耗时:{}", (end - start)/1000f);
        }
        return SUCCESS;
    }
    
    /**
     * @param object
     * @return
     */
    private BatchQueryTrackingCommand buildBatchQueryCommand(JSONObject json) {
    	BatchQueryTrackingCommand command = new BatchQueryTrackingCommand();
        command.setCtx(CommandContext.getContext());
        String trackingNos =  null;
        Set<String> keys = json.keySet();
        for(String key : keys){
        	String keyTemp = key.toLowerCase();
        	if(PARAM_TRACKINGNOS_LOWER.equals(keyTemp)){
        		trackingNos = json.getString(key);
        		break;
        	}
        }
        
        if (StringUtils.isBlank(trackingNos)) {
        	throw new ApiException(ErrorCode.FIELD_NOT_NULL, PARAM_TRACKINGNOS);
        }
        // 将\n \t 及空格转换成逗号统一处理
        Pattern p = Pattern.compile("\n\\s*|\t\\s*");
        Matcher m = p.matcher(trackingNos);
        trackingNos = m.replaceAll(",");
        // 空格、分号、逗号、换行
        String[] arr = trackingNos.replaceAll(" +", " ").replace(" ", ",").replace(";", ",").split(",");
        List<String> trackingNoList = new ArrayList<String>();
        for(String trackingNo : arr){
        	if(trackingNoList.contains(trackingNo)){
        		continue;
        	}
        	trackingNoList.add(trackingNo);
        }
        if (trackingNoList.size() > 500) {
            throw new ApiException(ErrorCode.FIELD_TRACKING_NO_OUT_RANGE);
        }
        command.setKeys(trackingNoList);
        return command;
    }
    
    
    /**
     * 轨迹数据处理
     * 
     * @param result
     */
    private List<TrackingVo> buildTrackingFromList(List<com.winit.tp.spi.trace.vo.TrackingVo> result,String language) {
        List<TrackingVo> data = new ArrayList<TrackingVo>();
        if (null == result) {
            return data;
        }
        Iterator<com.winit.tp.spi.trace.vo.TrackingVo> it = result.iterator();
        while (it.hasNext()) {
        	TrackingVo trackingVo = new TrackingVo();
        	com.winit.tp.spi.trace.vo.TrackingVo tracking = it.next();
        	trackingVo.setDestination(tracking.getDestination());
        	trackingVo.setOrderNo(tracking.getOrderNo());
        	trackingVo.setOrigin(tracking.getOrigin());
        	trackingVo.setPickupMode(tracking.getDispatchType());
        	trackingVo.setStatus(tracking.getStatus());
        	trackingVo.setTrackingNo(tracking.getTrackingNo());
        	trackingVo.setVendorName(tracking.getVendorName());
        	// 增加承运人code/是否带跟踪服务/货物跟踪网址/标准承运商
        	trackingVo.setCarrierCode(tracking.getCarrierCode());
        	trackingVo.setStandardCarrier(tracking.getStandardCarrier());
        	trackingVo.setTrackingUrl(tracking.getTrackingUrl());
        	trackingVo.setIsTracked(tracking.getIsTracked());
            List<com.winit.tp.spi.trace.vo.TraceVo> traces = tracking.getTrace();
            if (null == traces) {
            	continue;
            }
            List<TraceVo> trackVoList = new ArrayList<TraceVo>();
            for (com.winit.tp.spi.trace.vo.TraceVo t :traces)
            {
            	TraceVo traceVo = new TraceVo();
            	traceVo.setEventCode(t.getCode());
            	traceVo.setEventDescription(t.getDesc());
            	traceVo.setEventStatus(t.getStatus());
            	traceVo.setLastEvent(t.getLastEvent() == null?"N":t.getLastEvent());
            	traceVo.setLocation(t.getLocation());
            	traceVo.setOperator(t.getOperator());
            	traceVo.setType(t.getType());
            	Calendar cal = Calendar.getInstance();
            	cal.setTime(t.getDate());
            	cal.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            	traceVo.setDate(cal.getTime());//按北京时间转换
            	traceVo.setTrackingType(t.getTrackingType());
            	trackVoList.add(traceVo);
            }
            
            Collections.sort(trackVoList, new Comparator<TraceVo>(){
				@Override
				public int compare(TraceVo o1, TraceVo o2) {
				        if (null != o1 && null != o2) {
				            Date o1d = o1.getDate();
				            Date o2d = o2.getDate();
				            if (null != o1d && null != o2d) {
				                return o1d.after(o2d)? 1 : -1;
				            } else if (null != o1d) {
				                return 1;
				            } else if (null != o2d) {
				                return -1;
				            }
				        }
				        return 0;
				    }
            });
            
            trackingVo.setTrace(trackVoList);
            data.add(trackingVo);
        }
        return data;
    }
    
    /**
     * 轨迹数据处理
     * 
     * @param result
     */
    private List<TrackingVo> buildVerdorTrackingFromList(List<com.winit.tp.spi.trace.vo.TrackingVo> result,String language) {
        List<TrackingVo> data = new ArrayList<TrackingVo>();
        if (null == result) {
            return data;
        }
        Iterator<com.winit.tp.spi.trace.vo.TrackingVo> it = result.iterator();
        while (it.hasNext()) {
        	TrackingVo trackingVo = new TrackingVo();
        	com.winit.tp.spi.trace.vo.TrackingVo tracking = it.next();
        	trackingVo.setDestination(tracking.getDestination());
        	trackingVo.setOrderNo(tracking.getOrderNo());
        	trackingVo.setOrigin(tracking.getOrigin());
        	trackingVo.setPickupMode(tracking.getDispatchType());
        	trackingVo.setStatus(tracking.getStatus());
        	trackingVo.setTrackingNo(tracking.getTrackingNo());
        	trackingVo.setVendorName(tracking.getVendorName());
        	trackingVo.setCarrier(tracking.getCarrier());
            List<com.winit.tp.spi.trace.vo.TraceVo> traces = tracking.getTrace();
            if (null == traces) {
            	continue;
            }
            List<TraceVo> trackVoList = new ArrayList<TraceVo>();
            for (com.winit.tp.spi.trace.vo.TraceVo t :traces)
            {
	            	TraceVo traceVo = new TraceVo();
	            	traceVo.setEventCode(t.getCode());
	            	traceVo.setEventDescription(t.getDesc());
	            	traceVo.setEventStatus(t.getStatus());
	            	traceVo.setLastEvent(t.getLastEvent() == null?"N":t.getLastEvent());
	            	traceVo.setLocation(t.getLocation());
	            	traceVo.setOperator(t.getOperator());
	            	traceVo.setType(t.getType());
	            	Calendar cal = Calendar.getInstance();
	            	cal.setTime(t.getDate());
	            	cal.setTimeZone(TimeZone.getTimeZone("GMT+8"));
	            	traceVo.setDate(cal.getTime());//按北京时间转换
	            	trackVoList.add(traceVo);
            }
            
            Collections.sort(trackVoList, new Comparator<TraceVo>(){
				@Override
				public int compare(TraceVo o1, TraceVo o2) {
				        if (null != o1 && null != o2) {
				            Date o1d = o1.getDate();
				            Date o2d = o2.getDate();
				            if (null != o1d && null != o2d) {
				                return o1d.after(o2d)? -1 : 1;
				            } else if (null != o1d) {
				                return -1;
				            } else if (null != o2d) {
				                return 1;
				            }
				        }
				        return 0;
				    }
            });
            
            trackingVo.setTrace(trackVoList);
            data.add(trackingVo);
        }
        return data;
    }
    
    
    @RequestMapping(value = "/getTracking")
    public String query(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {

        Object obj = requestMsg.getData();
        BatchQueryTrackingCommand command = null;

        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            command = this.buildCommand(json);
            // 轨迹平台or卖家网站接口调用  默认卖家网站
            if(command.getPlatform()==null||command.getPlatform().equals("")){
            	command.setPlatform("seller");
            }
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        // 调用接口查询订单
        if (null != command.getKeys()) {
            List<com.winit.tp.spi.trace.vo.TrackingVo> result = trackingService.batchQueryTracking(command);
            List<TrackingBO> data = this.buildTracking(result,command.getCtx().getLanguageCountry());// 数据转换
            Collections.sort(data,  new Comparator<TrackingBO>() {
                @Override
                public int compare(TrackingBO o1, TrackingBO o2) {
                    if (null != o1 && null != o2) {
                        String o1d = getLatestTraceDate(o1);
                        String o2d = getLatestTraceDate(o2);
                        if (null != o1d && null != o2d) {
                            return o1d.compareTo(o2d) > 0 ? -1 : 1;
                        } else if (null != o1d) {
                            return -1;
                        } else if (null != o2d) {
                            return 1;
                        }
                    }
                    return 0;
                }

                /**
                 * 返回轨迹的最新时间
                 * 
                 * @return
                 */
                private String getLatestTraceDate(TrackingBO o) {
                    if (null == o.getTrace()) {
                        return null;
                    }
                    int len = o.getTrace().size();
                    if (len > 0) {
                        return o.getTrace().get(len - 1).getDate();
                    } else {
                        return null;
                    }
                }
			});// 数据排序
            responseMsg.setData(data);
        }
        return SUCCESS;
    }

    /**
     * @param object
     * @return
     */
    private BatchQueryTrackingCommand buildCommand(JSONObject json) {
        BatchQueryTrackingCommand command = new BatchQueryTrackingCommand();
        command.setCtx(CommandContext.getContext());
        String key = "trackingNo";
        command.getCtx().getLanguageCountry();
        if (json.containsKey(key)) {
            if (StringUtils.isNotBlank(json.getString(key))) {
                String trackingNo = json.getString(key);
                if (trackingNo != null) {
                    // 将\n \t 及空格转换成逗号统一处理
                    Pattern p = Pattern.compile("\n\\s*|\t\\s*");
                    Matcher m = p.matcher(trackingNo);
                    trackingNo = m.replaceAll(",");
                }
                String[] arr = null;
                if (trackingNo != null) {
                    // 空格、分号、逗号、换行
                    arr = trackingNo.replaceAll(" +", " ").replace(" ", ",").replace(";", ",").split(",");
                }
                arr = dataFilter(arr);
                if (arr.length > 30) {
                    throw new ApiException(ErrorCode.FIELD_TRACKING_NO_OUT_RANGE);
                }
                command.setKeys(Arrays.asList(arr));
            }
        } else {
            throw new ApiException(ErrorCode.FIELD_NOT_NULL, key);
        }
        return command;
    }

    /**
     * 轨迹数据处理
     * 
     * @param result
     */
    private List<TrackingBO> buildTracking(List<com.winit.tp.spi.trace.vo.TrackingVo> result,String language) {
        List<TrackingBO> data = new ArrayList<TrackingBO>();
        if (null == result) {
            return data;
        }
        Iterator<com.winit.tp.spi.trace.vo.TrackingVo> it = result.iterator();
        while (it.hasNext()) {
            TrackingBO tracking = new TrackingBO();
            com.winit.tp.spi.trace.vo.TrackingVo entry = it.next();
            tracking.setOrderNo(entry.getOrderNo());
            tracking.setTrackingNo(entry.getTrackingNo());
            tracking.setStartCountryCode(entry.getOrigin());
            tracking.setEndCountryCode(entry.getDestination());
            tracking.setStatus(entry.getStatus());
            tracking.setCarrier(entry.getCarrier());
            tracking.setPickupMode(entry.getDispatchType());
            List<TraceBO> traces = new ArrayList<TraceBO>();
            if (null != entry.getTrace()) {
                for (com.winit.tp.spi.trace.vo.TraceVo t : entry.getTrace()) {
                    TraceBO trace = new TraceBO();
                    trace.setDate(DateUtil.parse2StringByTimeZone(t.getDate(), DateUtil.FULL_DATE_STRING,TimeZone.getTimeZone("GMT+8")));//按北京时间转换
                    trace.setwTraceCode(t.getCode());
                    trace.setwTraceDesc(t.getDesc());
                    trace.setwTrackingStatus(t.getStatus());
                    trace.setLocation(t.getLocation());
                    traces.add(trace);
                }
            }
            
            Collections.sort(traces, new Comparator<TraceBO>(){
				@Override
				public int compare(TraceBO o1, TraceBO o2) {
				        if (null != o1 && null != o2) {
				            String o1d = o1.getDate();
				            String o2d = o2.getDate();
				            if (null != o1d && null != o2d) {
				                return o1d.compareTo(o2d) > 0 ? 1 : -1;
				            } else if (null != o1d) {
				                return 1;
				            } else if (null != o2d) {
				                return -1;
				            }
				        }
				        return 0;
				    }

			
            });
            
            tracking.setTrace(traces);
            data.add(tracking);
        }
        return data;
    }

    /**
     * 重复数据过滤
     * 
     * @param a
     * @return
     */
    private String[] dataFilter(String[] a) {
        Set<String> set = new HashSet<String>();
        set.addAll(Arrays.asList(a));
        return set.toArray(new String[0]);
    }
}
